# -*- coding: utf-8 -*-

"""
@author: Laowang
@contact: QQ:1125564921
@Created on: 2022/6/20
@Remark: 
"""

from keyword import iskeyword
from functools import partial
from types import FunctionType


class BaseGateway:
    """ 
    Base request

    @Mehtod :: request method
    @url :: request url
    @params :: request data
    @return :: Auto


    The easiest way to register is to pass in the callback function as a parameter, 
    otherwise you need to refactor the schema involved

    ::Return (status, data , response)
        ::parma status Request status is bool
        ::parma data   Response data is json 
        ::parma response  Origin Response
    """
    __slots__ = ()

    def __init__(self, main_engine, event_engine, gateway_name: str = None, proxy=None) -> None:
        self.main_engine = main_engine
        self.event_engine = event_engine
        self.gateway_name = gateway_name
        self.proxy = proxy

    def close(self): ...

# --------------
# Example
# --------------


def request(self, method, url, parmas):
    """"""
    return NotImplementedError


def get_server_time(self, method, url, kwargs):
    """ Get server time now """
    return NotImplementedError


def get_account(self, method, url, kwargs):
    """ Get account info """
    return NotImplementedError


def get_all_market_config(self, method, url, kwargs):
    """ Access all market config """
    return NotImplementedError


def get_klines(self, method, url, kwargs):
    """ Get Klines """
    return NotImplementedError


def get_ticker(self, method, url, kwargs):
    """ Aggregate market """
    return NotImplementedError


def get_tickers(self, method, url, kwargs):
    """ All aggregate market """
    return NotImplementedError


def get_depth(self, method, url, kwargs):
    """ Gain market depth """
    return NotImplementedError


def get_trades(self, method, url, kwargs):
    """ Get trade history """
    return NotImplementedError


def get_balance(self, method, url, kwargs):
    """ Get account balance """
    return NotImplementedError


def get_fund(self, method, url, kwargs):
    """ Gets the corresponding information for an account """
    return NotImplementedError


def send_order(self, method, url, kwargs):
    """ Order """
    return NotImplementedError


def send_orders(self, method, url, kwargs):
    """ Orders """
    return NotImplementedError


def cancel_order(self, method, url, kwargs):
    """ Cancel order """
    return NotImplementedError


def cancel_orders(self, method, url, kwargs):
    """ Cancel orders """
    return NotImplementedError


def get_order(self, method, url, kwargs):
    """ Get order """
    return NotImplementedError


def get_open_order(self, method, url, kwargs):
    """ Obtain outstanding orders """
    return NotImplementedError


def get_orders(self, method, url, kwargs):
    """ Obtain all orders information"""
    return NotImplementedError


# 缓存工厂
class GatewayManager:
    _cache = dict()

    def get_events(self, events_type: str, events):
        if events_type not in self._cache:
            self._cache[events_type] = events
        return self._cache[events_type]


class GatewayCache:

    gm = GatewayManager()

    @classmethod
    def get_events(cls, events_type: str, events=None):
        return cls.gm.get_events(events_type, events)


class GateWay(BaseGateway):

    def __init__(self, main_engine, event_engine, gateway_name: str = None, proxy=None) -> None:

        __new_events = []
        ON_EVENT = "ON_EVENT"

        events = GatewayCache.get_events(ON_EVENT)
        if not events:
            __events = getattr(self, ON_EVENT, [])
            GatewayCache.get_events(ON_EVENT, __events)
        else:
            __events = events

        super().__init__(main_engine, event_engine, gateway_name, proxy)
        for k, v in __events:
            if not isinstance(v, FunctionType) or iskeyword(k):
                continue
            # __func__ = partial(v.__wrapped__, self)
            # v.__wrapped__ = __func__
            self.__dict__[v.__name__] = partial(v, self)
            __new_events.append((k, partial(v, self)))

        self.__dict__["on_events"] = __new_events  # type list

        del __events

        # auto bind
        self.on_bind()
        print("[*] {} gateway init suceess".format(self.gateway_name))

    def __str__(self):
        return "<{}>".format(self.__class__.__name__)

    def on_bind(self):
        for _event_t, _event_f in self.on_events:
            self.event_engine.on_bind(_event_t, _event_f)

    def out_bind(self, _event_t: str, _event_f: FunctionType):
        self.event_engine.out_bind(_event_t, _event_f)
